
#include <assert.h>
#include <memory.h>
#include <stdio.h>
#include "cmap.h"

#pragma warning( disable:4996 )

SMap StlcMapCreate( size_t a_szKeyTypeSize, const char* a_pcKeyTypeName, size_t a_szValueTypeSize, const char* a_pcValueTypeName )
{
	SMap  stMap = {0};
	char  cTypeName[ TYPE_NAME_SIZE + 1 ] = {0};
	memset( &stMap, 0, sizeof( stMap ) );	

	assert( a_szKeyTypeSize > 0 && a_szValueTypeSize > 0);
	assert( NULL != a_pcKeyTypeName && NULL != a_pcValueTypeName );
	
	stMap.stPair = StlcPairCreate( a_szKeyTypeSize, a_pcKeyTypeName, a_szValueTypeSize, a_pcValueTypeName );
	
	StlcUnifyTypes( &stMap.stStlcType, a_szKeyTypeSize, a_pcKeyTypeName, NULL );
	sprintf( stMap.stStlcType.cTypeName, "map<%s,%s>", a_pcKeyTypeName, a_pcValueTypeName );
	sprintf( cTypeName, "pair<%s,%s>", a_pcKeyTypeName, a_pcValueTypeName );
	stMap.stMapTree = StlcRbTreeCreate( sizeof( SPair ), cTypeName );
	return stMap;
}

void StlcMapInit( PSMap a_pstMap, PFCompare a_pfnCompare )
{
	assert( NULL != a_pstMap );
	StlcPairInit( &a_pstMap->stPair, a_pfnCompare, NULL );
	assert( NULL != a_pstMap->stPair.pfnFirstCompare );
	StlcRbTreeInit( &a_pstMap->stMapTree , StlcComparePair, StlcPairDestroy );
}

bool StlcMapSameType( const SMap* a_pstMapFirst, const SMap* a_pstMapSecond )
{
	assert( NULL != a_pstMapFirst && NULL != a_pstMapSecond );
	return StlcPairSameType( &a_pstMapFirst->stPair, &a_pstMapSecond->stPair )
		&& StlcRbTreeSameType( &a_pstMapFirst->stMapTree, &a_pstMapSecond->stMapTree );
}

size_t StlcMapSize( const SMap* a_pstMap )
{
	assert( NULL != a_pstMap );
	return StlcRbTreeSize( &a_pstMap->stMapTree );
}

size_t StlcMapMaxSize( const SMap* a_pstMap )
{
	assert( NULL != a_pstMap );
	return StlcRbTreeMaxSize( &a_pstMap->stMapTree );
}

bool StlcMapEmpty( const SMap* a_pstMap )
{
	assert( NULL != a_pstMap );
	return StlcRbTreeEmpty( &a_pstMap->stMapTree );
}

bool StlcMapEqual( const SMap* a_pstMapFirst, const SMap* a_pstMapSecond )
{
	assert( NULL != a_pstMapFirst && NULL != a_pstMapSecond );
	if( StlcPairSameType( &a_pstMapFirst->stPair, &a_pstMapSecond->stPair ) )
	{
		return StlcRbTreeEqual( &a_pstMapFirst->stMapTree, &a_pstMapSecond->stMapTree );
	}
	return false;
}

bool StlcMapNotEqual( const SMap* a_pstMapFirst, const SMap* a_pstMapSecond )
{
	return !StlcMapEqual( a_pstMapFirst, a_pstMapSecond );
}

bool StlcMapLess( const SMap* a_pstMapFirst, const SMap* a_pstMapSecond )
{
	assert( NULL != a_pstMapFirst && NULL != a_pstMapSecond );
	assert( StlcPairSameType( &a_pstMapFirst->stPair, &a_pstMapSecond->stPair ) );
	return StlcRbTreeLess( &a_pstMapFirst->stMapTree, &a_pstMapSecond->stMapTree );
}

bool StlcMapGreat( const SMap* a_pstMapFirst, const SMap* a_pstMapSecond )
{
	assert( NULL != a_pstMapFirst && NULL != a_pstMapSecond );
	assert( StlcPairSameType( &a_pstMapFirst->stPair, &a_pstMapSecond->stPair ) );
	return StlcRbTreeGreat( &a_pstMapFirst->stMapTree, &a_pstMapSecond->stMapTree );
}

bool StlcMapLessEqual( const SMap* a_pstMapFirst, const SMap* a_pstMapSecond )
{
	assert( NULL != a_pstMapFirst && NULL != a_pstMapSecond );
	assert( StlcPairSameType( &a_pstMapFirst->stPair, &a_pstMapSecond->stPair ) );
	return StlcRbTreeLessEqual( &a_pstMapFirst->stMapTree, &a_pstMapSecond->stMapTree );
}

bool StlcMapGreatEqual( const SMap* a_pstMapFirst, const SMap* a_pstMapSecond )
{
	assert( NULL != a_pstMapFirst && NULL != a_pstMapSecond );
	assert( StlcPairSameType( &a_pstMapFirst->stPair, &a_pstMapSecond->stPair ) );
	return StlcRbTreeGreatEqual( &a_pstMapFirst->stMapTree, &a_pstMapSecond->stMapTree );
}

SIterator StlcMapBegin( const SMap* a_pstMap )
{
	SIterator stIterator = {0};
	assert( NULL != a_pstMap );

	stIterator = StlcRbTreeBegin( &a_pstMap->stMapTree );
	stIterator.eContainerType = ECRT_MAP;	
	stIterator.pstContainer = (void*)a_pstMap;	
	return stIterator;
}

SIterator StlcMapEnd( const SMap* a_pstMap )
{
	SIterator stIterator = {0};
	assert( NULL != a_pstMap );

	stIterator = StlcRbTreeEnd( &a_pstMap->stMapTree );
	stIterator.eContainerType = ECRT_MAP;
	stIterator.pstContainer = (void*)a_pstMap;	
	return stIterator;
}

SIterator StlcMapInsert( PSMap a_pstMap, const void* a_pKey, const void* a_pValue )
{
	SPair stPair = {0};
	assert( NULL != a_pstMap && NULL != a_pKey && NULL != a_pValue );
	stPair = StlcPairCreate( a_pstMap->stPair.szFirstTypeSize, NULL,
		 a_pstMap->stPair.szSecondTypeSize, NULL );
	StlcPairInit( &stPair, a_pstMap->stPair.pfnFirstCompare, NULL );
	StlcPairSet( &stPair, a_pKey, a_pValue );
	return StlcMapInsertPair( a_pstMap, &stPair );
}

SIterator StlcMapInsertPair( PSMap a_pstMap, const SPair* a_pstPair )
{
	SIterator stIterator = {0};
	assert( NULL != a_pstMap && NULL != a_pstPair );
	assert( StlcPairSameType( &a_pstMap->stPair, a_pstPair ) );
	
	stIterator = StlcRbTreeInsertUnique( &a_pstMap->stMapTree, a_pstPair );
	
	stIterator.eContainerType = ECRT_MAP;
	stIterator.pstContainer   = a_pstMap;		
	return stIterator;
}

void* StlcMapFind( const SMap* a_pstMap, ... )
{
	va_list   pArgList;
	SIterator stIterator = {0};
	assert( NULL != a_pstMap );
	va_start( pArgList, a_pstMap );
	StlcPairSet( &a_pstMap->stPair, pArgList, pArgList );
	stIterator = StlcRbTreeFindPosN( &a_pstMap->stMapTree, &a_pstMap->stPair, 0 );
	return ( StlcRbTreeIteratorEqual( &a_pstMap->stMapTree, stIterator, StlcRbTreeEnd( &a_pstMap->stMapTree ) ) ) 
		? NULL : ((PSPair)((PSRbtNode)stIterator.pcCurPos)->pcValue)->second;
}

SIterator StlcMapFindPos( const SMap* a_pstMap, ... )
{
	va_list   pArgList;
	SIterator stIterator = {0};
	assert( NULL != a_pstMap );
	va_start( pArgList, a_pstMap );
	StlcPairSet( &a_pstMap->stPair, pArgList, pArgList );
	stIterator = StlcRbTreeFindPosN( &a_pstMap->stMapTree, &a_pstMap->stPair, 0 );
	stIterator.eContainerType = ECRT_MAP;	
	stIterator.pstContainer = (PSMap)a_pstMap;
	return stIterator;
}

SIterator StlcMapErase( PSMap a_pstMap, ... )
{
	va_list   pArgList;
	SIterator stIterator = {0};
	assert( NULL != a_pstMap );
	va_start( pArgList, a_pstMap );
	StlcPairSet( &a_pstMap->stPair, pArgList, pArgList );	
	stIterator = StlcRbTreeErase( &a_pstMap->stMapTree, &a_pstMap->stPair );
	stIterator.eContainerType = ECRT_MAP;
	stIterator.pstContainer   = a_pstMap;
	return stIterator;
}

SIterator StlcMapErasePos( PSMap a_pstMap, SIterator a_stIterator )
{
	assert( NULL != a_pstMap && a_pstMap == a_stIterator.pstContainer );
	assert( ECRT_MAP == a_stIterator.eContainerType && EIRT_BIDIRECTIONAL == a_stIterator.eIteratorType );		

	a_stIterator.eContainerType = ECRT_RBTREE;
	a_stIterator.pstContainer   = &a_pstMap->stMapTree;
	a_stIterator = StlcRbTreeErasePos( &a_pstMap->stMapTree, a_stIterator );
	a_stIterator.eContainerType = ECRT_MAP;
	a_stIterator.pstContainer   = a_pstMap;
	return a_stIterator;
}

void StlcMapClear( PSMap a_pstMap )
{
	assert( NULL != a_pstMap );
	StlcRbTreeClear( &a_pstMap->stMapTree );
}

void StlcMapDestroy( PSMap a_pstMap )
{
	assert( NULL != a_pstMap );
	StlcPairDestroy( &a_pstMap->stPair );
	StlcRbTreeDestroy( &a_pstMap->stMapTree );
    memset( a_pstMap, 0, sizeof( SMap ) );
}

SIterator StlcMapIteratorCreate(void)
{
	SIterator stIterator = {0};
	memset( &stIterator, 0, sizeof( stIterator ) );	
	stIterator.eContainerType = ECRT_MAP;
	stIterator.eIteratorType  = EIRT_BIDIRECTIONAL;
	return stIterator;
}

bool StlcMapIteratorBelongTo( const SMap* a_pstMap, const SIterator a_stIterator )
{
	if( NULL != a_pstMap && NULL != a_stIterator.pcCurPos && a_pstMap == a_stIterator.pstContainer )
	{
		return true;
	}
	return false;
}

bool StlcMapIteratorEqual( const SMap* a_pstMap, const SIterator a_stIterFirst, const SIterator a_stIterSecond )
{
	assert(	StlcMapIteratorBelongTo( a_pstMap, a_stIterFirst )
		&& StlcMapIteratorBelongTo( a_pstMap, a_stIterSecond ) );
	if( 0 == memcmp( &a_stIterFirst, &a_stIterSecond, sizeof( SIterator ) ) )
	{
		return true;
	}
	return false;
}

void StlcMapIteratorGetValue( const SMap* a_pstMap,const SIterator a_stIterator, void* a_pValue )
{
	assert( StlcMapIteratorBelongTo( a_pstMap, a_stIterator ) && NULL != a_pValue );	
	assert( StlcMapSize( a_pstMap ) > 0 );
	assert( !StlcMapIteratorEqual( a_pstMap, a_stIterator, StlcMapEnd( a_pstMap ) ) );
	memcpy(	a_pValue, ((PSPair)((PSRbtNode)a_stIterator.pcCurPos)->pcValue)->second, 
		((PSPair)((PSRbtNode)a_stIterator.pcCurPos)->pcValue)->szSecondTypeSize );
}

void StlcMapIteratorGetPair( const SMap* a_pstMap, const SIterator a_stIterator, PSPair a_pstPair )
{
	assert( StlcMapIteratorBelongTo( a_pstMap, a_stIterator ) && NULL != a_pstPair );	
	assert( StlcMapSize( a_pstMap ) > 0 );
	assert( !StlcMapIteratorEqual( a_pstMap, a_stIterator, StlcMapEnd( a_pstMap ) ) );
	*a_pstPair = *((PSPair)((PSRbtNode)a_stIterator.pcCurPos)->pcValue);
}

const void* StlcMapIteratorGetPointer( const SMap* a_pstMap, const SIterator a_stIterator )
{
	assert( NULL != a_stIterator.pcCurPos );
	assert( StlcMapIteratorBelongTo( a_pstMap, a_stIterator ) );
	assert( !StlcMapIteratorEqual( a_pstMap, a_stIterator, StlcMapEnd( a_pstMap ) ) );	
	return ( StlcRbTreeIteratorEqual( &a_pstMap->stMapTree, a_stIterator, StlcRbTreeEnd( &a_pstMap->stMapTree ) ) ) 
		? NULL : ((PSPair)((PSRbtNode)a_stIterator.pcCurPos)->pcValue)->second;
}

void StlcMapIteratorNext( const SMap* a_pstMap, PSIterator a_pstIterator )
{
	assert( StlcMapIteratorBelongTo( a_pstMap, *a_pstIterator ) );
	a_pstIterator->eContainerType = ECRT_RBTREE;
	a_pstIterator->pstContainer   = (void*)&a_pstMap->stMapTree;
	StlcRbTreeIteratorNext( &a_pstMap->stMapTree, a_pstIterator );
	a_pstIterator->eContainerType = ECRT_MAP;
	a_pstIterator->pstContainer   = (void*)a_pstMap;
}

void StlcMapIteratorPrev( const SMap* a_pstMap, PSIterator a_pstIterator )
{
	assert( StlcMapIteratorBelongTo( a_pstMap, *a_pstIterator ) );
	a_pstIterator->eContainerType = ECRT_RBTREE;
	a_pstIterator->pstContainer   = (void*)&a_pstMap->stMapTree;
	StlcRbTreeIteratorPrev( &a_pstMap->stMapTree, a_pstIterator );
	a_pstIterator->eContainerType = ECRT_MAP;
	a_pstIterator->pstContainer   = (void*)a_pstMap;
}

void StlcMapIteratorNextN( const SMap* a_pstMap, PSIterator a_pstIterator, int a_nStep )
{
	assert( StlcMapIteratorBelongTo( a_pstMap, *a_pstIterator ) );
	a_pstIterator->eContainerType = ECRT_RBTREE;
	a_pstIterator->pstContainer   = (void*)&a_pstMap->stMapTree;
	StlcRbTreeIteratorNextN( &a_pstMap->stMapTree, a_pstIterator, a_nStep );
	a_pstIterator->eContainerType = ECRT_MAP;
	a_pstIterator->pstContainer   = (void*)a_pstMap;
}

void StlcMapIteratorPrevN( const SMap* a_pstMap, PSIterator a_pstIterator, int a_nStep )
{
	assert( StlcMapIteratorBelongTo( a_pstMap, *a_pstIterator ) );
	a_pstIterator->eContainerType = ECRT_RBTREE;
	a_pstIterator->pstContainer   = (void*)&a_pstMap->stMapTree;
	StlcRbTreeIteratorPrevN( &a_pstMap->stMapTree, a_pstIterator, a_nStep );
	a_pstIterator->eContainerType = ECRT_MAP;
	a_pstIterator->pstContainer   = (void*)a_pstMap;
}

int StlcMapIteratorDistance( const SMap* a_pstMap, const SIterator a_stIterFirst, const SIterator a_stIterSecond )
{
	int       nDistance = 0;
	SIterator stIterBegin = StlcRbTreeIteratorCreate();
	SIterator stIterEnd   = StlcRbTreeIteratorCreate();
	
	assert( StlcMapIteratorBelongTo( a_pstMap, a_stIterFirst ) );
	assert( StlcMapIteratorBelongTo( a_pstMap, a_stIterSecond ) );
	stIterBegin.pstContainer = (void*)&a_pstMap->stMapTree;
	stIterBegin.pcCurPos     = a_stIterFirst.pcCurPos;
	stIterEnd.pstContainer   = (void*)&a_pstMap->stMapTree;
	stIterEnd.pcCurPos       = a_stIterSecond.pcCurPos;
	return StlcRbTreeIteratorDistance( &a_pstMap->stMapTree, stIterBegin, stIterEnd );
}

bool StlcMapIteratorBefore( const SIterator a_stIterFirst, const SIterator a_stIterSecond )
{
	SIterator stIterFirst  = StlcRbTreeIteratorCreate();
	SIterator stIterSecond = StlcRbTreeIteratorCreate();

	assert( StlcMapIteratorBelongTo( a_stIterFirst.pstContainer, a_stIterSecond ) );
	stIterFirst.pstContainer  = &((PSMap)a_stIterFirst.pstContainer)->stMapTree;
	stIterFirst.pcCurPos      = a_stIterFirst.pcCurPos;
	stIterSecond.pstContainer = &((PSMap)a_stIterFirst.pstContainer)->stMapTree;
	stIterSecond.pcCurPos     = a_stIterSecond.pcCurPos;
	return StlcRbTreeIteratorBefore( stIterFirst, stIterSecond );
}